package com.demo;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

import java.util.Locale;

public class SpringBeanFactoryMain {
    /**
     *
     * 传统模式下： A对象创建B对象，C对象创建D对象 而且A对象要使用B对象还应该知道如何正确的创建B对象，也就是说对象的管理完全由应用程序控制
     * Ioc 控制反转 所有对象组件不再由应用程序自己创建和配置，而是由IoC容器负责，应用程序在运行过程中直接使用已经创建配置好的对象即可
     * DI  依赖注入 IoC容器创建和配置对象组件的方法，有Setter注入和构造方法注入两种方式
     * 由IoC容器负责管理组件的生命周期
     *
     */
    public static void main(String[] args) {
        //根据xml配置建造BeanFactory
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("application.xml");

        //获取相应的对象
        Object person = beanFactory.getBean("person");
        System.out.println(person instanceof Person);
        System.out.println(person);

        //或者根据自定义的获取对象
        Person personFromFactory = beanFactory.getBean("personFromFactory", Person.class);
        System.out.println(personFromFactory);

        //
        Object bean = beanFactory.getBean("&personFromFactory");
        System.out.println(bean instanceof PersonFactoryBean);
        PersonFactoryBean factoryBean=(PersonFactoryBean) bean;
        System.out.println("The initialization parameters are:"+factoryBean.getInitStr());

    }

    /**
     * XmlBeanFactory 方式
     */
    @Test
    public void testXmlBeanFactory(){

        BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));
        System.out.println(xmlBeanFactory.getBean("&personFromFactory"));
    }

    /**
     * 通过多个xml实例化容器
     */
    @Test
    public void testXmlBeanFactoryByArray(){
        //将文件路径作为字符串数组传给ApplicationContext构造器   Spring团队倾向于此做法
        ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[] {"application.xml", "daos.xml"});
        // an ApplicationContext is also a BeanFactory (via inheritance)
        BeanFactory factory = context;
        Object obj1 =factory.getBean("person");
        Person person =(Person)factory.getBean("personDao");
        System.out.println(obj1 instanceof Person);
        System.out.println(person.toString());

        // 或者应用<import/>元素加载
        // Note 所有的<import/>元素必 须在<bean/>元素之前完成bean定义的导入
        ApplicationContext context1 = new ClassPathXmlApplicationContext("services.xml");
        Person person1 =(Person)context1.getBean("personDao");
        System.out.println(person1.toString());
    }

    /**
     * 初始化和销毁回调方法
     */
    @Test
    public void testInitCall(){
        AbstractApplicationContext   beanFactory = new ClassPathXmlApplicationContext("services.xml");

        // 初始化
        Person person =(Person)beanFactory.getBean("personService");
        Person person1 =(Person)beanFactory.getBean("personService1");
        System.out.println(person1.toString());
        // 注册“关闭钩子”  JVM 关闭的时候   进行摧毁
        beanFactory.registerShutdownHook();
        System.out.println("Here");
    }

    /**
     *延迟初始化bean
     */
    @Test
    public void testLazyInit(){

        ApplicationContext context = new ClassPathXmlApplicationContext( "daos.xml");
        //获取当前Context->beanFactory->SingletonObjects的size  也可以打断点查看  目前延迟初始化是6 否则为7
        System.out.println(((DefaultListableBeanFactory)((ClassPathXmlApplicationContext)context).getBeanFactory()).getSingletonNames().length);

    }

    /**
     * Setter依赖注入  构造器依赖注入
     * 如果要用两种依赖方式同时存在   要添加无参的构造方法  并且Setter依赖注入情况下对象初始化也会调用无参的构造方法
     */
    @Test
    public void testSetter(){

        ApplicationContext context = new ClassPathXmlApplicationContext( "daos.xml");

        Person person =(Person)context.getBean("personDao");
        System.out.println(person.toString());

        Person person1 =(Person)context.getBean("person-constructor");
        System.out.println(person1.toString());
    }
    /**
     *  依赖注入对象
     */
    @Test
    public void testRoomSetter(){

        ApplicationContext context = new ClassPathXmlApplicationContext( "services.xml");

        Room room =(Room)context.getBean("roomService");
        //订阅-发布方式
        room.sendMessageToPerson("小棉","上网课");
        System.out.println(room.toString());
    }
    @Test
    public void testMessage(){
        MessageSource resources = new ClassPathXmlApplicationContext("message.xml");
        String message = resources.getMessage("coding", null, "Default", null);
        String message1 = resources.getMessage("argument.x", new String []{"212"}, "Default", null);
        System.out.println(message);
        System.out.println(message1);
    }


}
